package com.vonchange.headb.utils.named;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 带参数sql处理工具类
 */
public class HNamedParameterUtils {

	// 定义特殊字符（参考spring jdbc N多）
	private static final char[] PARAMETER_SEPARATORS = new char[] { '"', '\'', ':', '&', ',', ';', '(', ')', '|', '=', '+', '-', '*', '%', '/', '\\', '<', '>', '^' };

	/**
	 * 对带参数sql的统计式封装，便于后续肢解拼装（恐怖啊。。。。。）
	 * @param originalSql
	 * @return
	 */
	public static ParsedSql parserSqlStatement(String originalSql) {
		ParsedSql parsedSql = new ParsedSql(originalSql);
		Set<String> paramNames = new HashSet<String>();
		char[] sqlchars = originalSql.toCharArray();
		int namedParamCount = 0;
		int unNamedParamCount = 0;
		int totalParamCount = 0;
		int i = 0;
		while (i < sqlchars.length) {
			char statement = sqlchars[i];
			if (statement == ':' || statement == '&') {
				int j = i + 1;
				while (j < sqlchars.length && !isSeparatorsChar(sqlchars[j])) {
					j++;
				}
				if (j - i > 1) {
					String paramName = originalSql.substring(i + 1, j);
					if (!paramNames.contains(paramName)) {
						paramNames.add(paramName);
						namedParamCount++;
					}
					parsedSql.addParamNames(paramName, i, j);
					totalParamCount++;
				}
				i = j - 1;
			} else if (statement == '?') {
				unNamedParamCount++;
				totalParamCount++;
			}
			i++;
		}
		parsedSql.setNamedParamCount(namedParamCount);
		parsedSql.setUnnamedParamCount(unNamedParamCount);
		parsedSql.setTotalParamCount(totalParamCount);
		return parsedSql;
	}

	/**
	 * 获得不带参数的sql，即替换参数为？
	 * @param parsedSql
	 * @param params
	 */
	public static String substituteNamedParams(ParsedSql parsedSql, Map<String, Object> params) {
		String original = parsedSql.getOriginalSql();
		StringBuffer actual = new StringBuffer("");
		int lastIndex = 0;
		List<String> paramNames = parsedSql.getParamNames();
		for (int i = 0; i < paramNames.size(); i++) {
			int[] indexs = parsedSql.getParamIndexs(i);
			int startIndex = indexs[0];
			int endIndex = indexs[1];
			String paramName = paramNames.get(i);
			actual.append(original.substring(lastIndex, startIndex));
			if (params != null && params.containsKey(paramName)) {
				Object value = params.get(paramName);
				String prmStr = null;
				if (null != value) {
					Object[] arrValue = null;
					Class<?> retType = value.getClass();
					if (Collection.class.isAssignableFrom(retType)) {
						Collection<?> valueCol = (Collection<?>) value;
						arrValue = valueCol.toArray();
					} else 
					if (value instanceof Object[]) {
						arrValue = (Object[]) value;
					}
					if (null != arrValue) {
						int length=arrValue.length;
						StringBuffer fullStr = new StringBuffer();
						for (int j = 0; j < length; j++) {
							fullStr.append("?").append(",");
						}
						prmStr=fullStr.substring(0, fullStr.length()-1);
						actual.append(prmStr);
					}
				}
				if (null == prmStr) {
					actual.append("?");
				}
			} else {
				throw new RuntimeException(paramName + "占位符未赋值！");
			}
			lastIndex = endIndex;
		}
		actual.append(original.subSequence(lastIndex, original.length()));
		return actual.toString();
	}

	/**
	 * 获得sql所需参数
	 * @param parsedSql
	 * @param params
	 */
	public static List<Object> buildValueArray(ParsedSql parsedSql, Map<String, Object> params) {
		List<String> paramNames = parsedSql.getParamNames();
		List<Object> paramList= new ArrayList<Object>();
		if (parsedSql.getNamedParamCount() > 0 && parsedSql.getUnnamedParamCount() > 0) {
			throw new RuntimeException("请使用字符串！");
		}
		for (int i = 0; i < paramNames.size(); i++) {
			String keyName = paramNames.get(i);
			if (params.containsKey(keyName)) {
				Object value = params.get(keyName);
				boolean flag=false;
				if (null != value) {
					Object[] arrValue = null;
					Class<?> retType = value.getClass();
					if (Collection.class.isAssignableFrom(retType)) {
						Collection<?> valueCol = (Collection<?>) value;
						paramList.addAll(valueCol);
						flag=true;
					} else if (value instanceof Object[]) {
						arrValue = (Object[]) value;
						paramList.addAll(Arrays.asList(arrValue));
						flag=true;
					}
				}
				if(!flag){
				paramList.add(value);
				}
			}
		}
		return paramList;
	}

	protected static boolean isSeparatorsChar(char statement) {
		if (Character.isWhitespace(statement)) {
			return true;
		}
		for (int i = 0; i < PARAMETER_SEPARATORS.length; i++) {
			if (statement == PARAMETER_SEPARATORS[i]) {
				return true;
			}
		}
		return false;
	}
}
